package thebesttaskmanager.inputparser;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.GregorianCalendar;

public class InputParser {
	private static final String COMMAND_DEL = "delete";
	private static final String COMMAND_ADD = "add";
	private static final String COMMAND_DISPLAY = "display";
	private static final String COMMAND_EXIT = "exit";
	private static final String COMMAND_SORT = "sort";
	private static final String COMMAND_SEARCH = "search";
	private static final String COMMAND_UNDO = "undo";

	private ArrayList<String> dateformats;

	/**
	 * constructor. the supported date formats are set up here.
	 */
	public InputParser() {
		dateformats = new ArrayList<String>();

		dateformats.add(new String("ddMMyy HHmm"));
		dateformats.add(new String("ddMMyy HH:mm"));
		dateformats.add(new String("ddMMyy"));
		dateformats.add(new String("dd/MM/yy"));
		dateformats.add(new String("dd/MM/yyyy"));

	}

	/**
	 * reads in a string as input. then parses the string to return a Command
	 * consisting of startdate, enddate(deadline), command type, text.
	 * 
	 * @param line
	 *          the string that the user entered as input
	 * @return command a Command object
	 */
	public Command getCommand(String line) {
		Command command = new Command();

		line = line.trim().toLowerCase();

		try {
			if (line.startsWith(COMMAND_DEL)) {
				command.setCmd(COMMAND_DEL);
				command.setText(extractText(line));

			} else if (line.startsWith(COMMAND_ADD)) {
				String taskType = null;
				taskType = getTaskType(line);

				command.setCmd(COMMAND_ADD);

				try {
					if (taskType.equals("d")) {
						line = modifyDateWordsToDates(line, 'd');
						command.setText(extractText(line));
						command.setEndDate(extractDeadline(line));
					} else if (taskType.equals("t")) {
						line = modifyDateWordsToDates(line, 't');

						command.setText(extractText(line));
						command.setEndDate(extractEndDate(line));
						command.setStartDate(extractStartDate(line));
					} else {
						command.setText(extractText(line));
					}
				} catch (Exception e) {
					e.printStackTrace();
				}

			} else if (line.startsWith(COMMAND_DISPLAY)) {
				command.setCmd(COMMAND_DISPLAY);
				line = modifyDateWordsToDates(line, 'd');
				command.setText(extractText(line));
				command.setStartDate(extractStartDate(line));

			} else if (line.startsWith(COMMAND_SORT)) {
				command.setCmd(COMMAND_SORT);
			} else if (line.startsWith(COMMAND_SEARCH)) {
				command.setCmd(COMMAND_SEARCH);
				command.setText(extractText(line));
			} else if (line.startsWith(COMMAND_UNDO)) {
				command.setCmd(COMMAND_UNDO);
			} else if (line.startsWith(COMMAND_EXIT)) {
				command.setCmd(COMMAND_EXIT);
			}
		} catch (Exception e) {
			System.out.println(e);
			e.printStackTrace();
		}

		return command;
	}

	private String extractText(String line) throws Exception {
		if (line.contains("|")) {
			throw new Exception();
		}

		// clear off any leading whitespace
		line = line.trim();

		String substr = null;

		if (line.startsWith(COMMAND_ADD)) {
			String tempLine = line.replaceAll("[:|/]", "");
			tempLine = tempLine.replaceAll("[\\s]{2,}", " ");

			String dateStr = tempLine.split(" ")[1];

			boolean isDate = dateStr.matches("[\\d]{4,6}");

			if (isDate) {
				// System.out.println("SPLIT THIS: " + tempLine);

				if (tempLine
						.split("[\\d]{4,6}[\\s]+[\\d]{4}[\\s]+[\\d]{4,6}[\\s]+[\\d]{4}[\\s]+").length > 1) {
					substr = tempLine
							.split("[\\d]{4,6}[\\s]+[\\d]{4}[\\s]+[\\d]{4,6}[\\s]+[\\d]{4}[\\s]+")[1]
							.trim();
				} else if (tempLine
						.split("[\\d]{4,6}[\\s]+[\\d]{4}[\\s]+[\\d]{4,6}[\\s]+").length > 1) {
					substr = tempLine.split("[\\d]{4,6}[\\s]+[\\d]{4}[\\s]+[\\d]{4,6}[\\s]+")[1].trim();
				} else if (tempLine.split("[\\d]+[\\s]+[\\d]+[\\s]+").length > 1) {
					substr = tempLine.split("[\\d]+[\\s]+[\\d]+[\\s]+")[1].trim();
				} else {
					substr = tempLine.split("[\\d]+[\\s]+")[1].trim();
				}
			} else {
				int indx = tempLine.indexOf(' ');
				substr = tempLine.substring(indx).trim();
			}
		} else {
			int indx = line.indexOf(' ');
			substr = line.substring(indx).trim();
		}

		return substr;
	}

	private String getTaskType(String line) {
		String removeStr = COMMAND_ADD;

		// get the task type of the task
		// e.g. "addd task" gives you "d"
		String cmdType = line.replaceFirst(removeStr, "").split(" ")[0];

		return cmdType;
	}

	private Date extractStartDate(String line) throws Exception {
		return getDateFromLine(line, 0);
	}

	private Date extractEndDate(String line) throws Exception {
		return getDateFromLine(line, 1);
	}

	private Date extractDeadline(String line) throws Exception {
		return getDateFromLine(line, 0);
	}

	private String modifyDateWordsToDates(String line, char type) {
		line = line.replaceAll("[\\s]{2,}" , " ");
		int count = 0;
		
		for (String s : line.split(" ")) {
		
			if (s.matches("today")) {
				count ++;
				
				DateFormat dateFormat = new SimpleDateFormat("ddMMyy");
				String dateStr = dateFormat.format(new Date()).toString();
				line = line.replaceFirst("today", dateStr);
			} else if (s.matches("tomorrow")) {
				count ++;
				
				DateFormat dateFormat = new SimpleDateFormat("ddMMyy");
				GregorianCalendar calendar = new GregorianCalendar();
				calendar.add(calendar.DAY_OF_MONTH, 1);
				Date tmr = calendar.getTime();
				String dateStr = dateFormat.format(tmr).toString();
				line = line.replaceFirst("tomorrow", dateStr);
				
			} else if (s.startsWith(COMMAND_ADD) || s.startsWith(COMMAND_DISPLAY)) {
				continue;
			}	else if (s.matches("[\\D]+")){
				break;
			} 
			if (type == 'd' && count == 1) {
				break;
			} else if (type == 't' && count == 2) {
				break;
			}

		}
		
	
		return line;
	}

	/**
	 * extract from the entire line the substring that contains the date data of
	 * the command
	 * 
	 * @param line
	 * @return
	 */
	private String getDateInString(String line) {
//		System.out.println(line);
		String substr = line;
		int indx = substr.indexOf(' ');
		substr = substr.substring(indx).trim();

		substr = substr.replaceAll("[/|:]", "");
		substr = substr.replaceAll("[\\s]{2,}", " ");

		String dateStr = "";
		for (String s : substr.split(" ")) {

			if (s.matches("[\\d]{4,6}")) {
				dateStr = dateStr + s + " ";
			} else {
				break;
			}

		}

		return dateStr;
	}

	private Date getDateFromLine(String line, int num) throws Exception {
		if (num > 1 || num < 0) {
			throw new UnsupportedOperationException();
		}

		// get the substring of line that contains the string of the date
		String dateStr = getDateInString(line);
	//	System.out.println(dateStr + "<><>");
		// trim the string and convert any 2 or more whitespace into single
		// whitespace
		// e.g. "a  b" to become "a b"
		dateStr = dateStr.trim();
		dateStr = dateStr.replaceAll("[\\s]{2,}", " ");
		
		
		if (num == 1) {
			if (dateStr.matches("[\\d]{6}[\\s]+[\\d]{6}[\\s]*")) {
				dateStr = dateStr.replaceFirst("[\\d]{6}[\\s]+", "");
			} else if (dateStr
					.matches("[\\d]{6}[\\s]+[\\d]{4}[\\s]+[\\d]{6}[\\s]+[\\d]{4}[\\s]*")) {
				dateStr = dateStr.replaceFirst("[\\d]{6}[\\s]+[\\d]{4}[\\s]+", "");
			} else if (dateStr.matches("[\\d]{4,6}[\\s]+[\\d]{4}[\\s]+[\\d]{4,6}[\\s]+[\\d]{4}[\\s]*")){
				dateStr = dateStr.replaceFirst("[\\d]{4,6}[\\s]+[\\d]{4}[\\s]+", "");
			} else if (dateStr.matches("[\\d]{4,6}[\\s]+[\\d]{4}[\\s]+[\\d]{4,6}[\\s]*")){
				dateStr = dateStr.replaceFirst("[\\d]{4,6}[\\s]+[\\d]{4}[\\s]+", "");
			}
		} else {
			if (dateStr.matches("[\\d]{6}[\\s]+[\\d]{6}")) {

				dateStr = dateStr.replaceAll("([\\d]{6})([\\s]+[\\d]{6})", "$1");
			} else if (dateStr
					.matches("[\\d]{6}[\\s]+[\\d]{4}[\\s]+[\\d]{6}[\\s]+[\\d]{4}")) {
				dateStr = dateStr
						.replaceAll("([\\d]{6}[\\s]+[\\d]{4})([\\s]+[\\d]{6}[\\s]+[\\d]{4})", "$1");
			}
		}

		for (String s : dateformats) {
			// System.out.println(s);
			try {
				DateFormat df = new SimpleDateFormat(s);
				Date endDate = (Date) df.parseObject(dateStr);

				return endDate;

			} catch (Exception e) {
				// System.out.println(e);
			}
		}

		return null;
	}

	/*
	 * sample usage
	 */
	public static void main(String[] args) {

		InputParser ip = new InputParser();
		try {
			Command c = ip.getCommand("addd 201013 task");
			System.out.println(" > " + c.getText());
			System.out.println(" > " + c.getDeadline());

			c = ip.getCommand("addd  task");
			System.out.println(" > " + c.getText());
			System.out.println(" > " + c.getDeadline());

			c = ip.getCommand("addt 201013 211013 task");
			System.out.println(" > " + c.getText());
			System.out.println(" > " + c.getStartDate());
			System.out.println(" > " + c.getEndDate());

			c = ip.getCommand("addt 20/10/13 21/10/13 task");
			System.out.println(" > " + c.getText());
			System.out.println(" > " + c.getStartDate());
			System.out.println(" > " + c.getEndDate());

			c = ip.getCommand("addd 20/10/13 task");
			System.out.println(" > " + c.getText());
			System.out.println(" > " + c.getDeadline());

			c = ip.getCommand("    addd  200913   test input parser   ");
			System.out.println(" > " + c.getText());
			System.out.println(" > " + c.getDeadline());

			c = ip
					.getCommand("    addd  today   test input parser with date today   ");
			System.out.println(" > " + c.getText());
			System.out.println(" > " + c.getDeadline());
			
			c = ip
					.getCommand("    addt today 1600 tomorrow   today to tomorrow timed   ");
			System.out.println(" > " + c.getText());
			System.out.println(" > " + c.getStartDate());
			System.out.println(" > " + c.getEndDate());
			
			c = ip
					.getCommand(" display today ");
			System.out.println(" > " + c.getText());
			System.out.println(" > " + c.getStartDate());
		

			c = ip.getCommand("display floating");
			System.out.println(c.getCmd());
			System.out.println(c.getText());

			c = ip
					.getCommand(" aDDt 100913 1500  100913        1600 tutorial - by prof ");
			System.out.println(" > " + c.getText());
			System.out.println(" > " + c.getStartDate());
			System.out.println(" > " + c.getEndDate());

			c = ip
					.getCommand(" aDDt 100913 1500  100913        1600 tutorial - by prof ");
			System.out.println(" > " + c.getText());
			System.out.println(" > " + c.getStartDate());
			System.out.println(" > " + c.getEndDate());

			c = ip.getCommand("DElete    1");
			System.out.println(" > " + c.getText());

		} catch (Exception e) {
			System.out.println(e);
		}

	}

}
